from typing import List

from tortoise import Model
from tortoise.contrib.pydantic import PydanticModel
from tortoise.expressions import Q

from scheams import SuccessResponse, FailureResponse


async def create(create_model: Model, create_form: PydanticModel):
    """
    在数据库中增加一行数据。
    :param create_model: 增加的数据模型
    :param create_form: 增加数据的表单
    :return: 增加成功或者失败的响应
    """
    try:
        await create_model.create(**create_form.dict())
        return SuccessResponse(message="新建成功")
    except Exception as e:
        return FailureResponse(message="添加失败", error=e, code=400)


async def create_list(create_model: Model, create_form: List[PydanticModel]):
    """
    在数据库中增加多行数据。
    :param create_model: 增加的数据模型
    :param create_form: 增加数据的表单
    :return: 增加成功或者失败的响应
    """
    try:
        await create_model.bulk_create([create_model(**item.dict()) for item in create_form])
        return SuccessResponse(message="新建成功")
    except Exception as e:
        return FailureResponse(message="添加失败", error=e, code=400)


async def delete(delete_model: Model, pk: int):
    # try:
    #     await delete_model.filter(pk=pk).delete()
    #     return SuccessResponse(message="删除成功")
    # except Exception as e:
    #     return FailureResponse(message="删除失败",error=e, code=400)
    data = await delete_model.filter(pk=pk).delete()
    if data:
        return SuccessResponse(message="删除成功", data=data)
    else:
        return FailureResponse(message="删除失败", code=400)


async def delete_by_plan_id(delete_model: Model, delete_pydantic: PydanticModel, q: Q):
    data = await delete_model.filter(q).all()
    if len(data) == 0:
        return FailureResponse(message="找不到该方案", code=404)
    for item in data:
        result = await delete(delete_model, delete_pydantic.from_orm(item).id)
        if isinstance(result, SuccessResponse):
            continue
        else:
            return result
    result = await delete_model.all()
    return SuccessResponse(message="删除成功", data=result)


async def update(update_model: Model, update_form: PydanticModel, pk: int):
    data = await update_model.filter(pk=pk).update(**update_form.dict())
    if data:
        return SuccessResponse(data=data, message="修改成功")
    else:
        return FailureResponse(message="修改失败", code=400)


async def update_list_by_plan_id(update_model: Model, update_pydantic: PydanticModel,
                                 update_form: List[PydanticModel], q: Q):
    if len(update_form) < 1:
        return FailureResponse(message="修改后至少保留一条数据")
    data = await update_model.filter(q).all()
    if len(data) == 0:
        return FailureResponse(message="找不到该方案", code=404)
    result = await delete_by_plan_id(update_model, update_pydantic, q)
    if not isinstance(result, SuccessResponse):
        await create_list(update_model, [update_pydantic.from_orm(item) for item in data])
        return FailureResponse(message="修改失败")
    result = await create_list(update_model, update_form)
    if not isinstance(result, SuccessResponse):
        return FailureResponse(message="修改失败")
    return SuccessResponse(message="修改成功", data=result)


async def read(read_model: Model, q: Q, get_form: PydanticModel):
    data = get_form.from_orm(await read_model.filter(q).first())
    if data:
        return SuccessResponse(data=data, message="获取成功")
    else:
        return FailureResponse(message="获取失败", code=400)


async def get_list_by_id(read_model: Model, get_form: PydanticModel, q: Q):
    data = await read_model.filter(q).all()
    if data:
        return SuccessResponse(data=[get_form.from_orm(item) for item in data], message="获取成功")
    else:
        return FailureResponse(message="获取失败", code=400)


async def get_list(read_model: Model, get_form: PydanticModel, page: int, limit: int):
    if page == 0 or limit == 0:
        data = await read_model.all()
    else:
        skip = limit * (page - 1)
        data = await read_model.all().limit(limit).offset(skip)
    if data:
        return SuccessResponse(data=[get_form.from_orm(item) for item in data], message="获取成功")
    else:
        return FailureResponse(message="获取失败", code=400)
